home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 June: Reference Library / Dev.CD Jun 96 RL / Dev.CD Jun 96 RL.toast / Technical Documentation / develop / develop Issue 24 / develop Issue 24 code / Scriptable Database 1.0a15 / Blue / MoreStrings.cp < prev    next >
Encoding:
Text File  |  1996-02-19  |  16.7 KB  |  494 lines  |  [TEXT/CWIE]

  1. #include "MoreStrings.h"
  2. #include "Exceptions.h"
  3.  
  4. #include <AERegistry.h>
  5. #include <TextUtils.h>
  6.  
  7.  
  8.  
  9.  
  10. //========================================================================================
  11. // CLASS TString
  12. //========================================================================================
  13.  
  14.  
  15. TString::TString() :
  16.     fStr(nil),
  17.     fStringScript(smSystemScript),
  18.     fStringLanguage(scriptDefLang),
  19.     fActualSizeInBytes(0),
  20.     fMaximumSizeInBytes(256),
  21.     fStorageAllocatedInHeap(true)
  22. {
  23.     fStr = new unsigned char[fMaximumSizeInBytes];
  24.     fStr[0] = 0;
  25. }
  26.  
  27. TString::TString(const TString& string) :
  28.     fStr(nil),
  29.     fStringScript(smSystemScript),
  30.     fStringLanguage(scriptDefLang),
  31.     fActualSizeInBytes(0),
  32.     fMaximumSizeInBytes(string.StringLength()),
  33.     fStorageAllocatedInHeap(true)
  34. {
  35.     fStr = new unsigned char[fMaximumSizeInBytes];
  36.     fStr[0] = 0;
  37.     
  38.     *this = string;
  39. }
  40.  
  41. TString::TString(const TDescriptor& desc) :
  42.     fStr(nil),
  43.     fStringScript(smSystemScript),
  44.     fStringLanguage(scriptDefLang),
  45.     fActualSizeInBytes(0),
  46.     fMaximumSizeInBytes(256),
  47.     fStorageAllocatedInHeap(true)
  48. {
  49.     fStr = new unsigned char[fMaximumSizeInBytes];
  50.     fStr[0] = 0;
  51.     
  52.     *this = desc;
  53. }
  54.  
  55. TString::TString(UInt32 maximumSize) :
  56.     fStr(nil),
  57.     fStringScript(smSystemScript),
  58.     fStringLanguage(scriptDefLang),
  59.     fActualSizeInBytes(0),
  60.     fMaximumSizeInBytes(maximumSize),
  61.     fStorageAllocatedInHeap(true)
  62. {
  63.     fStr = new unsigned char[fMaximumSizeInBytes];
  64.     fStr[0] = 0;
  65. }
  66.  
  67. TString::TString(unsigned char* stringExternalStorage, UInt32 maximumSize, UInt32 currentSizeInBytes, ScriptCode stringScript, LangCode stringLanguage) :
  68.     fStr(stringExternalStorage),
  69.     fStringScript(stringScript),
  70.     fStringLanguage(stringLanguage),
  71.     fMaximumSizeInBytes(maximumSize),
  72.     fStorageAllocatedInHeap(false)
  73. {
  74.     this->SetLength(currentSizeInBytes);
  75. }
  76.  
  77. TString::TString(unsigned char* stringExternalStorage) :
  78.     fStr(stringExternalStorage),
  79.     fStringScript(smSystemScript),
  80.     fStringLanguage(scriptDefLang),
  81.     fActualSizeInBytes(stringExternalStorage[0]),
  82.     fMaximumSizeInBytes(256),
  83.     fStorageAllocatedInHeap(false)
  84. {
  85. }
  86.  
  87. TString::~TString()
  88. {
  89.     if(fStorageAllocatedInHeap)
  90.         delete fStr;
  91. }
  92.  
  93.  
  94. //----------------------------------------------------------------------------------------
  95. // TString::TDescriptor: 
  96. //----------------------------------------------------------------------------------------
  97. TString::operator TDescriptor() const
  98. {
  99.     TDescriptor result;
  100.     
  101.     //
  102.     // If this string doesn't have any particular script code associated with it,
  103.     // then build a typeChar descriptor.  Otherwise, make a typeIntlText descriptor.
  104.     //
  105.     if(this->StringScript() == smSystemScript)
  106.     {
  107.         result.SetDescriptorData(TConstDataReference(typeChar, (char*)this->TextStart(), this->StringLength()));
  108.     }    
  109.     else
  110.     {
  111.         SInt32 dataSize = this->StringLength() + (sizeof(ScriptCode) + sizeof(LangCode));
  112.         struct IntlText* theIntlText = (struct IntlText*) new char[dataSize];
  113.         theIntlText->theScriptCode = this->StringScript();
  114.         theIntlText->theLangCode = this->StringLanguage();
  115.         TUpdataDataReference updateReference(typeChar, &theIntlText->theText[0], 0, this->StringLength());
  116.         updateReference.CopyFrom(TConstDataReference(typeChar, (char*)this->TextStart(), this->StringLength()));
  117.         
  118.         result.SetDescriptorData(updateReference);
  119.         delete theIntlText;
  120.     }
  121.     
  122.     return result;
  123. } // TString::operator TDescriptor 
  124.  
  125. //----------------------------------------------------------------------------------------
  126. // TString::operator=: 
  127. //----------------------------------------------------------------------------------------
  128. TString& TString::operator=(const TString& rhs)
  129. {
  130.     this->Replace(kStringStart, kStringEnd, rhs);
  131.  
  132.     return *this;
  133. } // TString::operator= 
  134.  
  135. //----------------------------------------------------------------------------------------
  136. // TString::operator=: 
  137. //----------------------------------------------------------------------------------------
  138. TString& TString::operator=(const TDescriptor& desc)
  139. {
  140.     if(desc.DescriptorType() == typeIntlText)
  141.     {
  142.         SInt32 dataSize = desc.DataSize();
  143.         this->ExpandToFit(dataSize);
  144.         struct IntlText* theIntlText = (struct IntlText*) new char[dataSize];
  145.         TUpdataDataReference updateReference(typeIntlText, (char*)theIntlText, 0, dataSize);
  146.         desc.GetDescriptorData(updateReference);
  147.         SInt32 rawTextSize = updateReference.DataLength() - (sizeof(ScriptCode) + sizeof(LangCode));
  148.         
  149.         //
  150.         // In addition to the string, we'll also get a header with
  151.         // script and language code information in it stuck on the
  152.         // beginning of our data.
  153.         //
  154.         TString theIntlString((unsigned char*)theIntlText->theText, rawTextSize, rawTextSize, theIntlText->theScriptCode, theIntlText->theLangCode);
  155.         *this = theIntlString;
  156.         delete theIntlText;
  157.     }
  158.     if(desc.DescriptorType() == typeChar)
  159.     {
  160.         SInt32 dataSize = desc.DataSize();
  161.         this->ExpandToFit(dataSize);
  162.         TUpdataDataReference updateReference(typeChar, (char*)this->TextStart(), this->StringLength(), this->MaximumSizeInBytes());
  163.         desc.GetDescriptorData(updateReference);
  164.         fStringScript = smSystemScript;
  165.         fStringLanguage = scriptDefLang;
  166.         this->SetLength(updateReference.DataLength());
  167.     }
  168.     else
  169.     {
  170.         OSErr err = noErr;
  171.         TDescriptor coercedDescriptor = desc.AttemptToCoerce(typeIntlText, err);
  172.         if(coercedDescriptor.DescriptorType() == typeIntlText)
  173.             *this = coercedDescriptor;
  174.         else
  175.         {
  176.             coercedDescriptor.Dispose();
  177.             coercedDescriptor = desc.AttemptToCoerce(typeChar, err);
  178.             if(coercedDescriptor.DescriptorType() == typeChar)
  179.                 *this = coercedDescriptor;
  180.         }
  181.         coercedDescriptor.Dispose();
  182.     }
  183.     
  184.     return *this;
  185. } // TString::operator= 
  186.  
  187. //----------------------------------------------------------------------------------------
  188. // TString::SetLength: 
  189. //----------------------------------------------------------------------------------------
  190. void TString::SetLength(UInt32 newLength)
  191. {
  192.     fActualSizeInBytes = newLength;
  193.     if(newLength < 255)
  194.         fStr[0] = newLength;
  195.     else
  196.         fStr[0] = 255;
  197. } // TString::Length 
  198.  
  199. //----------------------------------------------------------------------------------------
  200. // TString::CorrectInternalLength: 
  201. //----------------------------------------------------------------------------------------
  202. void TString::CorrectInternalLength() const
  203. {
  204.     if(fStr[0] != 255)
  205.         ((TString*)this)->fActualSizeInBytes = fStr[0];
  206.     else if(fActualSizeInBytes < 255)
  207.         ((TString*)this)->fActualSizeInBytes = 255;
  208. } // TString::Length 
  209.  
  210. //----------------------------------------------------------------------------------------
  211. // TString::Length: 
  212. //----------------------------------------------------------------------------------------
  213. UInt32 TString::StringLength() const
  214. {
  215.     this->CorrectInternalLength();
  216.     
  217.     return fActualSizeInBytes;
  218. } // TString::Length 
  219.  
  220. //----------------------------------------------------------------------------------------
  221. // TString::SizeInBytes: 
  222. //----------------------------------------------------------------------------------------
  223. UInt32 TString::SizeInBytes() const
  224. {
  225.     //
  226.     // Add one for the length byte
  227.     //
  228.     return this->StringLength() + 1;
  229. } // TString::SizeInBytes 
  230.  
  231. //----------------------------------------------------------------------------------------
  232. // TString::MaximumSizeInBytes: 
  233. //----------------------------------------------------------------------------------------
  234. UInt32 TString::MaximumSizeInBytes() const
  235. {
  236.     return fMaximumSizeInBytes;
  237. } // TString::MaximumSizeInBytes 
  238.  
  239. //----------------------------------------------------------------------------------------
  240. // TString::Empty: 
  241. //----------------------------------------------------------------------------------------
  242. Boolean TString::Empty() const
  243. {
  244.     return (this->StringLength() == 0);
  245. } // TString::Empty 
  246.  
  247. //----------------------------------------------------------------------------------------
  248. // TString::ClearString: 
  249. //----------------------------------------------------------------------------------------
  250. void TString::ClearString()
  251. {
  252.     this->SetLength(0);
  253. } // TString::ClearString 
  254.  
  255. //----------------------------------------------------------------------------------------
  256. // TString::CompareStringOrder: 
  257. //----------------------------------------------------------------------------------------
  258. SInt16 TString::CompareStringOrder(const TString& compareWith) const
  259. {
  260.     return IUTextOrder(this->TextStart(), compareWith.TextStart(),
  261.         this->StringLength(), compareWith.StringLength(),
  262.         this->StringScript(), compareWith.StringScript(),
  263.         this->StringLanguage(), compareWith.StringLanguage());
  264. }
  265.  
  266. //----------------------------------------------------------------------------------------
  267. // TString::Equivalent: 
  268. //----------------------------------------------------------------------------------------
  269. Boolean TString::Equivalent(const TString& compareWith) const
  270. {
  271.     Boolean isEqual = false;
  272.     
  273.     isEqual = (this->CompareStringOrder(compareWith) == 0);
  274.     
  275.     return isEqual;
  276. } // TString::Equivalent 
  277.  
  278. //----------------------------------------------------------------------------------------
  279. // TString::Equal: case insensitive, diacritical sensitive
  280. //----------------------------------------------------------------------------------------
  281. Boolean TString::Equal(const TString& compareWith) const
  282. {
  283.     return this->Equivalent(compareWith);
  284. } // TString::Equal 
  285.  
  286. //----------------------------------------------------------------------------------------
  287. // TString::ExactlyEqual: case sensitive, diacritical sensitive
  288. //----------------------------------------------------------------------------------------
  289. Boolean TString::ExactlyEqual(const TString& compareWith) const
  290. {
  291.     return this->Equivalent(compareWith);
  292. } // TString::ExactlyEqual 
  293.  
  294. //----------------------------------------------------------------------------------------
  295. // TString::NearlyEqual: case insensitive, diacritical insensitive
  296. //----------------------------------------------------------------------------------------
  297. Boolean TString::NearlyEqual(const TString& compareWith) const
  298. {
  299.     return this->Equivalent(compareWith);
  300. } // TString::NearlyEqual 
  301.  
  302. //----------------------------------------------------------------------------------------
  303. // TString::FindOffset: 
  304. //----------------------------------------------------------------------------------------
  305. SInt32 TString::FindOffset(const TString& searchPattern) const
  306. {
  307.     SInt32        foundStartIndex = kSubstringNotFound;
  308.     
  309.     if(searchPattern.StringLength() > 0)
  310.     {
  311.         //
  312.         // Search through this string to see if we can find the
  313.         // search pattern at any offset.
  314.         //
  315.         // Skip comparisons at byte offsets that are in the middle
  316.         // of multi-byte characters.
  317.         //
  318.         UInt32 bytesToCheck = this->StringLength() - searchPattern.StringLength();
  319.         UInt32 currentPosition = 0;
  320.         while((currentPosition < bytesToCheck) && (foundStartIndex == kSubstringNotFound))
  321.         {
  322.             //
  323.             // If thisCharType is smSingleByte or smFirstByte, then we want
  324.             // to compare at this postion.  If it is smLastByte or smMiddleByte,
  325.             // then skip it. 
  326.             //
  327.             // CharacterByteType requires System 7.1
  328.             //
  329.             SInt16 thisCharType = CharacterByteType((char*)this->TextStart(), currentPosition, this->StringScript());
  330.             if((thisCharType == smFirstByte) || (thisCharType == smFirstByte))
  331.             {
  332.                 TString subString((unsigned char*)(this->TextStart() + currentPosition), searchPattern.StringLength(), searchPattern.StringLength(), this->StringScript(), this->StringLanguage());
  333.                 if(subString.Equivalent(searchPattern))
  334.                     foundStartIndex = currentPosition;
  335.             }
  336.  
  337.             ++currentPosition;
  338.         }
  339.     }
  340.     
  341.     return foundStartIndex;
  342. } // TString::Contains 
  343.  
  344. //----------------------------------------------------------------------------------------
  345. // TString::Contains: 
  346. //----------------------------------------------------------------------------------------
  347. Boolean TString::Contains(const TString& searchPattern) const
  348. {
  349.     return this->FindOffset(searchPattern) != kSubstringNotFound;
  350. } // TString::Contains 
  351.  
  352. //----------------------------------------------------------------------------------------
  353. // TString::Delete: 
  354. //----------------------------------------------------------------------------------------
  355. void TString::Delete(UInt32 destStartIndex, UInt32 destEndIndex)
  356. {
  357.     if((destStartIndex >= 0) && (destStartIndex < this->StringLength()) && (destEndIndex > destStartIndex))
  358.     {
  359.         UInt32 bytesToMove = this->StringLength() - destEndIndex;
  360.         
  361.         if(bytesToMove > 0)
  362.         {
  363.             CopyMemory(this->TextStart() + destEndIndex, this->TextStart() + destStartIndex, bytesToMove);
  364.             this->SetLength(destStartIndex + bytesToMove);
  365.         }
  366.         else
  367.         {
  368.             this->SetLength(destStartIndex);
  369.         }
  370.     }
  371. }
  372.  
  373. //----------------------------------------------------------------------------------------
  374. // TString::ExpandToFit
  375. //----------------------------------------------------------------------------------------
  376. void TString::ExpandToFit(UInt32 spaceRequired)
  377. {
  378.     if(fStorageAllocatedInHeap && (this->MaximumSizeInBytes() < spaceRequired))
  379.     {
  380.         //
  381.         // Round up the size to the next even multiple of 'kStringAllocationChunk'
  382.         //
  383.         UInt32 newAllocationSize = ((((spaceRequired + kStringAllocationChunk - 1) / kStringAllocationChunk)) * kStringAllocationChunk);
  384.         unsigned char* newStringStorage = new unsigned char[newAllocationSize];
  385.         
  386.         CopyMemory(&fStr[0], newStringStorage, this->SizeInBytes());
  387.         delete fStr;
  388.         fStr = newStringStorage;
  389.         fMaximumSizeInBytes = newAllocationSize;
  390.     }
  391. }
  392.  
  393. //----------------------------------------------------------------------------------------
  394. // TString::InsertAfter: 
  395. //----------------------------------------------------------------------------------------
  396. Boolean TString::InsertAfter(UInt32 destStartIndex, const TString& replaceWith)
  397. {
  398.     UInt32 bytesToInsert = replaceWith.StringLength();
  399.     Boolean insertionFit = true;
  400.     
  401.     if((destStartIndex >= 0) && (bytesToInsert > 0))
  402.     {
  403.         //
  404.         // Make room for the insert, if possible.  If there
  405.         // isn't enough space, then truncate
  406.         //    
  407.         this->ExpandToFit(this->StringLength() + bytesToInsert);
  408.         SInt32 overflowAmount = (this->StringLength() + bytesToInsert + 1) - this->MaximumSizeInBytes();
  409.         if(overflowAmount > 0)
  410.         {
  411.             insertionFit = false;
  412.             SInt32 newLength = this->StringLength() - overflowAmount;
  413.             if(newLength < destStartIndex)
  414.                 newLength = destStartIndex;
  415.             overflowAmount -= (this->StringLength() - newLength);
  416.             this->SetLength(newLength);
  417.             bytesToInsert -= overflowAmount;
  418.         }
  419.         
  420.         if(bytesToInsert > 0)
  421.         {
  422.             //
  423.             // Calculate how many bytes we need to copy after the
  424.             // starting index in order to make room for the insertion.
  425.             //
  426.             if(destStartIndex > this->StringLength())
  427.                 destStartIndex = this->StringLength();
  428.             UInt32 bytesToMove = this->StringLength() - destStartIndex;
  429.             
  430.             if(bytesToMove > 0)
  431.                 CopyMemory(this->TextStart() + destStartIndex, this->TextStart() + destStartIndex + bytesToInsert, bytesToMove);
  432.             CopyMemory(replaceWith.TextStart(), this->TextStart() + destStartIndex, bytesToInsert);
  433.             
  434.             this->SetLength(this->StringLength() + bytesToInsert);
  435.             
  436.             //
  437.             // Any time you replace some text in a string, the entire
  438.             // script and language of the destination string takes
  439.             // on the script and language of the inserted text.
  440.             //
  441.             // Such is the life of single-script strings.  :<
  442.             //
  443.             fStringScript = replaceWith.StringScript();
  444.             fStringLanguage = replaceWith.StringLanguage();
  445.         }
  446.     }
  447.     
  448.     return insertionFit;
  449. }
  450.  
  451. //----------------------------------------------------------------------------------------
  452. // TString::Replace: 
  453. //----------------------------------------------------------------------------------------
  454. void TString::Replace(UInt32 destStartIndex, UInt32 destEndIndex, const TString& replaceWith)
  455. {
  456.     this->Delete(destStartIndex, destEndIndex);
  457.     this->InsertAfter(destStartIndex, replaceWith);
  458. } // TString::Replace 
  459.  
  460. //----------------------------------------------------------------------------------------
  461. // TString::Append: 
  462. //----------------------------------------------------------------------------------------
  463. void TString::Append(const TString& appendString)
  464. {
  465.     this->InsertAfter(kStringEnd, appendString);
  466. } // TString::Append 
  467.  
  468. //----------------------------------------------------------------------------------------
  469. // TString::Prefix: 
  470. //----------------------------------------------------------------------------------------
  471. void TString::Prefix(const TString& prefixString)
  472. {
  473.     this->InsertAfter(kStringStart, prefixString);
  474. } // TString::Prefix 
  475.  
  476. //----------------------------------------------------------------------------------------
  477. // TString::ConvertToStr255
  478. //----------------------------------------------------------------------------------------
  479. void TString::ConvertToStr255(Str255 destination)
  480. {
  481.     TString outputString(destination, 255);
  482.  
  483.     outputString = *this;
  484. }
  485.  
  486. //========================================================================================
  487. // CLASS TStackBasedString
  488. //========================================================================================
  489.  
  490. TStackBasedString::TStackBasedString(const TString& sourceStr) : TString(fStringStorage, kStackBasedStringStorageUnits * sizeof(unsigned char))
  491. {
  492.     *this = sourceStr;
  493. }
  494.